#include <stdint.h>
#include <stdio.h>
#include <stdbool.h>
#include "mfifoblock.h"

int mfifoblock_map(mblock_t *mb, uint8_t *buffer, uint16_t block_num, uint16_t single_block_size)
{
    MFIFOBLOCK_ASSERT(mb);
    MFIFOBLOCK_ASSERT(buffer);

    for (uint16_t i = 0; i < block_num; i++)
    {
        (mb + i)->buffer = buffer + (i * single_block_size);
    }

    return 0;
}

int mfifoblock_init(mfifoblock_t *mfb, mblock_t *mb, uint16_t block_num, uint16_t single_block_size)
{
    MFIFOBLOCK_ASSERT(mfb);
    MFIFOBLOCK_ASSERT(mb);

    mfb->mb = mb;
    mfb->block_num = block_num;
    mfb->single_block_size = single_block_size;

    return 0;
}

int mfifoblock_reset(mfifoblock_t *mfb)
{
    MFIFOBLOCK_ASSERT(mfb);

    mfb->read_index = 0;
    mfb->write_index = 0;
    mfb->read_count = 0;
    mfb->write_count = 0;

    return 0;
}

bool mfifoblock_is_full(mfifoblock_t *mfb)
{
    MFIFOBLOCK_ASSERT(mfb);

    if ((uint16_t)(mfb->write_count - mfb->read_count) == mfb->block_num)
    {
        return true;
    }
    return false;
}

bool mfifoblock_is_empty(mfifoblock_t *mfb)
{
    MFIFOBLOCK_ASSERT(mfb);

    if (mfb->write_count == mfb->read_count)
    {
        return true;
    }
    return false;
}

bool mfifoblock_not_full(mfifoblock_t *mfb)
{
    MFIFOBLOCK_ASSERT(mfb);

    if ((uint16_t)(mfb->write_count - mfb->read_count) == mfb->block_num)
    {
        return false;
    }
    return true;
}

bool mfifoblock_not_empty(mfifoblock_t *mfb)
{
    MFIFOBLOCK_ASSERT(mfb);

    if (mfb->write_count != mfb->read_count)
    {
        return true;
    }
    return false;
}

uint16_t mfifoblock_data_len(mfifoblock_t *mfb)
{
    // 0 - 0xFFFF = 1
    // 1 - 0xFFFF = 2
    return (uint16_t)(mfb->write_count - mfb->read_count);
}

uint16_t mfifoblock_space_len(mfifoblock_t *mfb)
{
    return (uint16_t)(mfb->block_num) - mfifoblock_data_len(mfb);
}

int mfifoblock_write_block_get(mfifoblock_t *mfb, uint8_t **buf)
{
    MFIFOBLOCK_ASSERT(mfb);

    if ((uint16_t)(mfb->write_count - mfb->read_count) >= mfb->block_num)
    {
        *buf = NULL;
        return 1;
    }

    if (mfb->write_index == mfb->block_num)
    {
        mfb->write_index = 0;
    }

    *buf = (mfb->mb + mfb->write_index)->buffer;

    return 0;
}

int mfifoblock_write_block_increase(mfifoblock_t *mfb, uint16_t bufsize)
{
    MFIFOBLOCK_ASSERT(mfb);

    (mfb->mb + mfb->write_index)->buffer_len = bufsize;
    mfb->write_index += 1;
    mfb->write_count += 1;

    return 0;
}

int mfifoblock_read_block_get(mfifoblock_t *mfb, uint8_t **buf, uint16_t *bufsize)
{
    MFIFOBLOCK_ASSERT(mfb);

    if (mfb->write_count == mfb->read_count)
    {
        if (buf != NULL)
        {
            *buf = NULL;
        }
        if (bufsize != NULL)
        {
            *bufsize = 0;
        }
        return 2;
    }

    if (mfb->read_index == mfb->block_num)
    {
        mfb->read_index = 0;
    }

    if (buf != NULL)
    {
        *buf = (mfb->mb + mfb->read_index)->buffer;
    }

    if (bufsize != NULL)
    {
        *bufsize = (mfb->mb + mfb->read_index)->buffer_len;
    }

    return 0;
}

int mfifoblock_read_block_increase(mfifoblock_t *mfb)
{
    MFIFOBLOCK_ASSERT(mfb);

    mfb->read_index += 1;
    mfb->read_count += 1;

    return 0;
}
